/**
 * 
 */
package top.ibase4j.core.support.jedis;

import java.io.Serializable;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.InitializingBean;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisShardInfo;
import top.ibase4j.core.support.cache.ICacheManager;
import top.ibase4j.core.util.DataUtil;
import top.ibase4j.core.util.InstanceUtil;

/**
 * 
 * @author ShenHuaJie
 * @version 2018年3月8日 下午6:13:43
 */
public class ConnectionFactory implements InitializingBean, ICacheManager {
    private GenericObjectPoolConfig poolConfig;
    private String clusterAddress;
    private String shardedAddress;
    private int maxRedirects = 5;
    private String host;
    private int port;
    private String password;
    private String master;
    private String sentinels;

    private ICacheManager cacheManager;
    private int connectTimeout = 2000;
    private int readTimeout = 2000;

    public ConnectionFactory() {
    }

    public ConnectionFactory(GenericObjectPoolConfig poolConfig) {
        this.poolConfig = poolConfig;
    }

    public ConnectionFactory(GenericObjectPoolConfig poolConfig, String shardedAddress) {
        this.poolConfig = poolConfig;
        this.shardedAddress = shardedAddress;
    }

    public ConnectionFactory(GenericObjectPoolConfig poolConfig, String master, String sentinels) {
        this.poolConfig = poolConfig;
        this.master = master;
        this.sentinels = sentinels;
    }

    public ConnectionFactory(GenericObjectPoolConfig poolConfig, String clusterAddress, int maxRedirects) {
        this.poolConfig = poolConfig;
        this.clusterAddress = clusterAddress;
        this.maxRedirects = maxRedirects;
    }

    public ConnectionFactory(GenericObjectPoolConfig poolConfig, String host, int port, String password) {
        this.poolConfig = poolConfig;
        this.host = host;
        this.port = port;
        if (DataUtil.isNotEmpty(password)) {
            this.password = password;
        }
    }

    public void setPoolConfig(GenericObjectPoolConfig poolConfig) {
        this.poolConfig = poolConfig;
    }

    public void setClusterAddress(String clusterAddress) {
        this.clusterAddress = clusterAddress;
    }

    public void setShardedAddress(String shardedAddress) {
        this.shardedAddress = shardedAddress;
    }

    public void setMaxRedirects(int maxRedirects) {
        this.maxRedirects = maxRedirects;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setPassword(String password) {
        if (DataUtil.isNotEmpty(password)) {
            this.password = password;
        }
    }

    public void setMaster(String master) {
        this.master = master;
    }

    public void setSentinels(String sentinels) {
        this.sentinels = sentinels;
    }

    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    public void afterPropertiesSet() throws Exception {
        if (poolConfig == null) {
            throw new RuntimeException("线程池配置错误");
        }
        if (DataUtil.isNotEmpty(shardedAddress)) {
            List<JedisShardInfo> shards = InstanceUtil.newArrayList();
            String[] hostPorts = shardedAddress.split(",");
            for (String hostPort : hostPorts) {
                String[] hostAndPort = hostPort.split(":");
                if (hostAndPort.length != 2 || !StringUtils.isNumeric(hostAndPort[1])) {
                    throw new RuntimeException("属性配置错误");
                }
                JedisShardInfo shardInfo = new JedisShardInfo(hostAndPort[0], Integer.valueOf(hostAndPort[1]),
                    connectTimeout);
                shardInfo.setPassword(password);
                shards.add(shardInfo);
            }
            cacheManager = new JedisShardedTemplate(poolConfig, shards);
        } else if (DataUtil.isNotEmpty(clusterAddress)) {
            String[] addrs = clusterAddress.split(",");
            Set<HostAndPort> jedisClusterNodes = InstanceUtil.newHashSet();
            for (String addr : addrs) {
                jedisClusterNodes.add(HostAndPort.parseString(addr));
            }
            cacheManager = new JedisClusterTemplate(jedisClusterNodes, connectTimeout, readTimeout, maxRedirects,
                password, poolConfig);
        } else if (DataUtil.isNotEmpty(master) && DataUtil.isNotEmpty(sentinels)) {
            Set<String> set = InstanceUtil.newHashSet(sentinels.split(","));
            cacheManager = new JedisSentinelTemplate(master, set, poolConfig, connectTimeout, password);
        } else if (DataUtil.isNotEmpty(host) && DataUtil.isNotEmpty(host)) {
            cacheManager = new JedisTemplate(poolConfig, host, port, connectTimeout, password);
        } else {
            throw new RuntimeException("redis连接配置错误");
        }
    }

    public Object get(String key) {
        return cacheManager.get(key);
    }

    public Set<Object> getAll(String pattern) {
        return cacheManager.getAll(pattern);
    }

    public void set(String key, Serializable value, int seconds) {
        cacheManager.set(key, value, seconds);
    }

    public void set(String key, Serializable value) {
        cacheManager.set(key, value);
    }

    public Boolean exists(String key) {
        return cacheManager.exists(key);
    }

    public void del(String key) {
        cacheManager.del(key);
    }

    public void delAll(String pattern) {
        cacheManager.delAll(pattern);
    }

    public String type(String key) {
        return cacheManager.type(key);
    }

    public Boolean expire(String key, int seconds) {
        return cacheManager.expire(key, seconds);
    }

    public Boolean expireAt(String key, long unixTime) {
        return cacheManager.expireAt(key, unixTime);
    }

    public Long ttl(String key) {
        return cacheManager.ttl(key);
    }

    public Object getSet(String key, Serializable value) {
        return cacheManager.getSet(key, value);
    }

    public boolean lock(String key) {
        return cacheManager.lock(key);
    }

    public void unlock(String key) {
        cacheManager.unlock(key);
    }

    public void hset(String key, Serializable field, Serializable value) {
        cacheManager.hset(key, field, value);
    }

    public Object hget(String key, Serializable field) {
        return cacheManager.hget(key, field);
    }

    public void hdel(String key, Serializable field) {
        cacheManager.hdel(key, field);
    }

    public boolean setnx(String key, Serializable value) {
        return cacheManager.setnx(key, value);
    }

    public Long incr(String key) {
        return cacheManager.incr(key);
    }

    public void setrange(String key, long offset, String value) {
        cacheManager.setrange(key, offset, value);
    }

    public String getrange(String key, long startOffset, long endOffset) {
        return cacheManager.getrange(key, startOffset, endOffset);
    }

    public Object get(String key, Integer expire) {
        return cacheManager.get(key, expire);
    }

    public Object getFire(String key) {
        return cacheManager.getFire(key);
    }

    public Set<Object> getAll(String pattern, Integer expire) {
        return cacheManager.getAll(pattern, expire);
    }
}
